/*
 Name:		ControllerSystem.ino
 Created:	2025-11-13 10:03:54
 Author:	君无悔
*/

// 包含库
//-------------------------------------------------------------------------------------------------------------
#include <Ticker.h>
#include <ArduinoJson.h>
#include <ArduinoJson.hpp>
#include <NTPClient.h>  // NTP库
#include <WiFi.h>
#include <WiFiUdp.h>

#include "NRF.h"                  // NRF接收
#include "Keys.h"                 // 按键
#include "Screen.h"               // 屏幕
#include "LED.h"                  // LED 
#include "pins_config.h"          // 引脚配置（包含WiFi配置）
#include "controller_keys.h"      // 按键引脚定义
#include "STZhongsong18.h"        // 中文字体库
#include "tetris.h"               // 俄罗斯方块游戏
#include "snake.h"                // 贪吃蛇游戏
#include "brick.h"                // 打砖块游戏
#include "plane.h"                // 飞机大战游戏
#include "num2048.h"              // 2048游戏
#include "cube.h"                 // 陀螺仪立方体
#include "menu.h"                 // 菜单模块
#include "pickup.h"               // 皮卡遥控模块
#include "tank.h"                 // 坦克遥控模块
#include "keysTest.h"             // 按键测试模块
#include "battery.h"              // 电池电量管理模块
#include "pic/weather/rainbow.h"  // 彩虹图标
#include "pic/weather/snow2.h"    // 雪花图标

// WiFi连接状态标志
bool wifiConnected = false;

//-------------------------------------------------------实例化对象------------------------------------------------------
NRF nrf;              // 通信模块
Keys keys;            // 按键
Screen screen;        // 屏幕
LED led;              // 板载LED
Tetris tetrisGame;    // 俄罗斯方块游戏
Snake snakeGame;      // 贪吃蛇游戏
Brick brickGame;      // 打砖块游戏
Plane planeGame;      // 飞机大战游戏
Num2048 num2048Game;  // 2048游戏
Cube cubeApp;         // 陀螺仪立方体

// 电池管理对象
Battery battery(screen);  // 电池电量管理

// NRF遥控对象
Pickup pickupControl(screen, keys, nrf);  // 皮卡遥控
Tank tankControl(screen, keys, nrf);      // 坦克遥控

// 菜单对象
Menu mainMenu(screen, keys);
NRFMenu nrfMenu(screen, keys);
GameMenu gameMenu(screen, keys);
VSMenu vsMenu(screen, keys);
InfoMenu infoMenu(screen, keys);
SystemMenu systemMenu(screen, keys);

// region 获取天气的参数
WiFiClient client;
String reqRes = "/v3/weather/weatherInfo?city=528300&key=87d09dca42f2ff103271e60b67a31112";  // 高德API服务,百度即可
const char *host = "restapi.amap.com";
const int httpPort = 80;
// end 获取天气的参数

// region 获取时间的参数
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "ntp.aliyun.com");  // NTP服务器地址
int currentMonth = 0;                            // 月
int monthDay = 0;                                // 日
int currentHour = 0;                             // 时
int currentMinute = 0;                           // 分
int currentSec = 0;                              // 秒
int weekDay = 0;                                 // 星期

// end 获取时间的参数

// 函数声明
//---------------------------------------------1.NRF遥控--------------------------------------------------------
void pickup();     // 1.1 皮卡
void truck();      // 1.2 货车
void tank();       // 1.3 坦克
void drone();      // 1.4 无人机
void excavator();  // 1.5 挖掘机
void ship();       // 1.6 舰船

//---------------------------------------------2.本机游戏-------------------------------------------------------
void snake();    // 2.1 贪吃蛇
void brick();    // 2.2 打砖块
void plane();    // 2.3 飞机大战
void num2048();  // 2.4 2048
void tetris();   // 2.5 俄罗斯方块

//----------------------------------------------3.双人对战------------------------------------------------------
void ball();  // 3.1 弹球

//----------------------------------------------4.网络信息------------------------------------------------------
void bilibili();  // 4.1 哔哩哔哩
void weather();   // 4.2 天气预报
void stock();     // 4.3 股票基金

//----------------------------------------------5.蓝牙手柄------------------------------------------------------
void btGamepad();  // 5. 蓝牙手柄

//----------------------------------------------6.系统设置------------------------------------------------------
void keysTest();  // 6.1 按键测试
void cube();      // 6.2 陀螺仪立方体

//----------------------------------------------一级菜单回调------------------------------------------------------
void NRFControl();  // 1.NRF遥控菜单
void localGame();   // 2.本机游戏菜单
void VSGame();      // 3.双人对战菜单
void netInfo();     // 4.网络信息菜单
void systemSet();   // 6.系统设置菜单

void setup() {
  Serial.begin(115200);                 // 设置波特率
  nrf.init(ID, NRF_LEVEL);              // (遥控器ID, 置通信功率)
  keys.init(ID);                        // 按键初始化
  screen.init();                        // 屏幕初始化
  led.init();                           // 板载LED初始化
  battery.init();                       // 电池检测初始化
  screen.spr.loadFont(STZhongsong18);   // 加载自定义中文字库
  screen.textWhite();
  screen.drawString("Loading...", 120, 300);  // Loading
  screen.drawScreen();                        // 渲染

  // WiFi连接，带超时机制
  Serial.println("Connecting to WiFi...");
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);  // 连接wifi

  unsigned long wifiStartTime = millis();
  const unsigned long WIFI_TIMEOUT = 10000;  // 10秒超时

  // 判断是否连接成功，带超时退出
  while (WiFi.status() != WL_CONNECTED && (millis() - wifiStartTime < WIFI_TIMEOUT)) {
    delay(500);
    Serial.print(".");
  }

  // 检查WiFi连接结果
  if (WiFi.status() == WL_CONNECTED) {
    wifiConnected = true;
    Serial.println("\nWiFi Connected!");
    Serial.print("IP Address: ");
    Serial.println(WiFi.localIP());

    // 初始化NTP时间客户端
    timeClient.begin();
    timeClient.setTimeOffset(28800);  // 东八区，+8小时
  } else {
    wifiConnected = false;
    Serial.println("\nWiFi Connection Failed!");
    Serial.println("Continuing without network features...");
  }

  // 设置菜单回调函数
  mainMenu.setNRFControlCallback(NRFControl);
  mainMenu.setLocalGameCallback(localGame);
  mainMenu.setVSGameCallback(VSGame);
  mainMenu.setNetInfoCallback(netInfo);
  mainMenu.setBtGamepadCallback(btGamepad);
  mainMenu.setSystemSetCallback(systemSet);

  nrfMenu.setPickupCallback(pickup);
  nrfMenu.setTruckCallback(truck);
  nrfMenu.setTankCallback(tank);
  nrfMenu.setDroneCallback(drone);
  nrfMenu.setExcavatorCallback(excavator);
  nrfMenu.setShipCallback(ship);

  gameMenu.setSnakeCallback(snake);
  gameMenu.setBrickCallback(brick);
  gameMenu.setPlaneCallback(plane);
  gameMenu.setNum2048Callback(num2048);
  gameMenu.setTetrisCallback(tetris);

  vsMenu.setBallCallback(ball);

  infoMenu.setBilibiliCallback(bilibili);
  infoMenu.setWeatherCallback(weather);
  infoMenu.setStockCallback(stock);

  systemMenu.setKeysTestCallback(keysTest);
  systemMenu.setCubeCallback(cube);

  // 显示主菜单
  mainMenu.show();
}

void loop() {
  // ================================================================
  // 系统级后台任务调度
  // ================================================================

  // 1. 按键状态扫描更新（每10ms执行一次）
  static unsigned long lastKeyScanTime = 0;
  if (millis() - lastKeyScanTime >= 10) {
    keys.bounce_update();  // 更新按键消抖状态
    keys.kvs_update();     // 更新所有按键值
    lastKeyScanTime = millis();
  }

  // 2. 电池电量定期采样（每5秒执行一次）
  static unsigned long lastBatteryCheckTime = 0;
  if (millis() - lastBatteryCheckTime >= 5000) {
    battery.getPercentage();  // 定期采样电池电量
    lastBatteryCheckTime = millis();
  }

  // 3. WiFi时间同步（如果WiFi已连接，每小时更新一次）
  static unsigned long lastTimeUpdateTime = 0;
  if (wifiConnected && (millis() - lastTimeUpdateTime >= 3600000)) {
    timeClient.update();  // 更新NTP时间
    lastTimeUpdateTime = millis();
  }

  // 4. 板载LED心跳指示（每2秒闪烁一次）
  static unsigned long lastLedBlinkTime = 0;
  static bool ledState = false;
  if (millis() - lastLedBlinkTime >= 2000) {
    ledState = !ledState;
    if (ledState) {
      led.on();
    } else {
      led.off();
    }
    lastLedBlinkTime = millis();
  }

  // 5. 串口状态输出（调试用，每10秒执行一次）
  static unsigned long lastSerialPrintTime = 0;
  if (millis() - lastSerialPrintTime >= 10000) {
    Serial.print("System Running | Battery: ");
    Serial.print(battery.getPercentage());
    Serial.print("% | WiFi: ");
    Serial.println(wifiConnected ? "Connected" : "Disconnected");
    lastSerialPrintTime = millis();
  }

  // 6. 系统看门狗（防止系统卡死）
  static unsigned long lastWatchdogTime = 0;
  if (millis() - lastWatchdogTime >= 30000) {
    // 每30秒检查一次系统状态
    Serial.println("Watchdog: System OK");
    lastWatchdogTime = millis();
  }

  // 主循环延时，减少CPU占用
  delay(10);  // 10ms延时，保证系统响应性
}

// ----------------------------------------- 以下是功能的具体实现 -----------------------------------------------

//----------------------------------------------一级菜单回调------------------------------------------------------
// 1.NRF遥控菜单
void NRFControl() {
  nrfMenu.show();
}

// 2.本机游戏菜单
void localGame() {
  gameMenu.show();
}

// 3.双人对战菜单
void VSGame() {
  vsMenu.show();
}

// 4.网络信息菜单
void netInfo() {
  infoMenu.show();
}

// 5.蓝牙手柄
void btGamepad() {
  Serial.println("5.蓝牙手柄");
}

// 6.系统设置菜单
void systemSet() {
  systemMenu.show();
}

//--------------------------------------------- 二级菜单 -------------------------------------------------------

//--------------------------------------------- 1.NRF遥控 -------------------------------------------------------
// 1.1 皮卡
void pickup() {
  // 调用封装的皮卡遥控功能
  pickupControl.main();
}

// 1.2 货车
void truck() {
  Serial.println("1.2 货车");
}

// 1.3 坦克
void tank() {
  Serial.println("1.3 坦克");
  // 调用封装的坦克遥控功能
  tankControl.main();
}

// 1.4 无人机
void drone() {
  Serial.println("1.4 无人机");
}

// 1.5 挖掘机
void excavator() {
  Serial.println("1.5 挖掘机");
}

// 1.6 舰船
void ship() {
  Serial.println("1.6 舰船");
}

//----------------------------------------------2.本机游戏-----------------------------------------------------
// 2.1 贪吃蛇
void snake() {
  Serial.println("2.1 贪吃蛇");
  // 调用封装的贪吃蛇游戏
  snakeGame.main(screen, keys);
  // 游戏结束后清屏并恢复菜单状态
  screen.clearAndCenter();
}

// 2.2 打砖块
void brick() {
  Serial.println("2.2 打砖块");
  // 调用封装的打砖块游戏
  brickGame.main(screen, keys);
  // 游戏结束后清屏并恢复菜单状态
  screen.clearAndCenter();
}

// 2.3 飞机大战
void plane() {
  Serial.println("2.3 飞机大战");
  // 调用封装的飞机大战游戏
  planeGame.main(screen, keys);
  // 游戏结束后清屏并恢复菜单状态
  screen.clearAndCenter();
}

// 2.4 2048
void num2048() {
  Serial.println("2.4 2048");
  // 调用封装的2048游戏
  num2048Game.main(screen, keys);
  // 游戏结束后清屏并恢复菜单状态
  screen.clearAndCenter();
}

// 2.5 俄罗斯方块
void tetris() {
  Serial.println("2.5 俄罗斯方块");
  // 调用封装的俄罗斯方块游戏
  tetrisGame.main(screen, keys);
  // 游戏结束后清屏并恢复菜单状态
  screen.clearAndCenter();
}

//---------------------------------------------3.双人对战------------------------------------------------------
// 3.1 弹球
void ball() {
  Serial.println(" 3.1 弹球");
}

//---------------------------------------------4.网络信息------------------------------------------------------
// 4.1 哔哩哔哩
void bilibili() {
  Serial.println("4.1 哔哩哔哩");
}

// 4.2 天气预报
void weather() {
  Serial.println("4.2 天气预报");

  // 检查WiFi连接状态
  if (!wifiConnected) {
    screen.clearAndCenter();
    screen.drawString("WiFi未连接", 120, 250);
    screen.drawString("无法获取天气信息", 120, 280);
    screen.drawScreen();
    delay(2000);
    return;
  }

  // TODO: 实现天气获取功能
  screen.clearAndCenter();
  screen.drawString("天气功能开发中", 120, 268);
  screen.drawScreen();
  delay(2000);
}

// 4.3 股票基金
void stock() {
  Serial.println("4.3 股票基金");
}

//---------------------------------------------6.系统设置------------------------------------------------------
// 6.1 按键测试
void keysTest() {
  drawKeys(screen, "按键测试");

  // 实时显示按键状态
  while (true) {
    updateKeys(screen, keys);

    // 同时按下2个前端按键，退出本功能
    if (keys.b.pressed() && keys.x.pressed()) {
      screen.spr.fillSprite(TFT_BLACK);  // 清屏
      screen.drawScreen();
      break;
    }

    delay(1);
  }
}

// 6.2 陀螺仪立方体
void cube() {
  Serial.println("6.2 陀螺仪立方体");
  // 调用封装的陀螺仪立方体功能
  cubeApp.main(screen, keys);
  // 功能结束后清屏并恢复菜单状态
  screen.clearAndCenter();
}

//--------------------------------------------- 工具方法 -------------------------------------------------------
// 电池状态显示
void drawBatteryStatus() {
  int batteryPercentage = battery.getPercentage();
  battery.drawIcon(100, 5, batteryPercentage);
}

// 获取时间
void get_time() {
  if (!wifiConnected) {
    Serial.println("无法获取时间：WiFi未连接");
    return;
  }

  timeClient.update();
  unsigned long epochTime = timeClient.getEpochTime();

  currentHour = timeClient.getHours();
  currentMinute = timeClient.getMinutes();
  currentSec = timeClient.getSeconds();
  weekDay = timeClient.getDay();

  struct tm *ptm = gmtime((time_t *)&epochTime);
  monthDay = ptm->tm_mday;
  currentMonth = ptm->tm_mon + 1;
}